package com.puzzlebazar.client.heyawake;

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.shared.EventHandler;
import com.puzzlebazar.client.puzzle.model.History;
import com.puzzlebazar.client.puzzle.model.HistoryMove;
import com.puzzlebazar.client.puzzle.model.MoveTimer;
import com.puzzlebazar.client.squaregrid.control.ComponentCallbackAdapter;
import com.puzzlebazar.client.squaregrid.control.HighlightControl;
import com.puzzlebazar.client.squaregrid.control.RectangleCallback;
import com.puzzlebazar.client.squaregrid.control.RectangleControl;
import com.puzzlebazar.client.squaregrid.view.CellHighlighterOutline;
import com.puzzlebazar.client.squaregrid.view.ComponentHighlighter;
import com.puzzlebazar.client.util.Recti;
import com.puzzlebazar.client.util.Releasable;
import com.puzzlebazar.client.util.Vec2i;

public class CreateRoomsState extends HeyawakeState implements Releasable {

	private final ClickCallback clickCallback = new ClickCallback();
	private final RoomCallback roomCallback = new RoomCallback();
	
	private final HighlightRoomConstraints highlightContraints;


	private CellHighlighterOutline cellHighlighter = null;
	private CellHighlighterOutline rectHighlighter = null;
	private HighlightControl highlightControl = null;
	private RectangleControl rectangleControl = null;

	private boolean drawingRectangle = false;
	private Object mouseDownInRoom = null;


	/**
	 * Creates a controller state for room creation
	 * 
	 * @param model The associated model
	 * @param view The view for the heyawake
	 * @param controller The associated controller
	 * @param history History track into which to add the moves
	 * @param moveTimer The move timer
	 */
	public CreateRoomsState(HeyawakeModel model, HeyawakeView view, 
			HeyawakeController controller, History history, MoveTimer moveTimer) {
		super(model, view, controller, history, moveTimer);


		highlightContraints = new HighlightRoomConstraints( model );


	
	}
	
	@Override
	public void enter() {
		controller.enableEdit( false );

		drawingRectangle = false;

		if( cellHighlighter == null ) {
			cellHighlighter = new CellHighlighterOutline(
					view.getHighlightLayer(),
					"yellowfill",
					"CRSCell");
			cellHighlighter.setPixelSize( 3 );
		}
		
		if( rectHighlighter == null ) {
			rectHighlighter = new CellHighlighterOutline(
					view.getHighlightLayer(),
					"yellowfill",
					"CRSRect");
			rectHighlighter.setPixelSize( 3 );
		}
		
		ComponentHighlighter highlighter1 = new ComponentHighlighter(null,null,cellHighlighter);
		ComponentHighlighter highlighter2 = new ComponentHighlighter(null,null,rectHighlighter);

		if( highlightControl != null )
			highlightControl.release();
		if( rectangleControl != null )
			rectangleControl.release();
		
		highlightControl = new HighlightControl(
				highlightContraints,
				highlighter1,
				view.getControlDecorator() );

				
		rectangleControl = new RectangleControl(
				highlighter2,
				view.getControlDecorator() );
				
		
		enableCallbacks();
		
	}

	@Override
	public void exit() {
		controller.enableEdit( true );

		disableCallbacks();

		if( highlightControl != null )
			highlightControl.release();
		highlightControl = null;
		if( rectangleControl != null )
			rectangleControl.release();
		rectangleControl = null;
		
		drawingRectangle = false;		
	}


	private class RoomCallback implements RectangleCallback {

		@Override
		public boolean rectangleBegin( Vec2i loc, MouseEvent<? extends EventHandler> event ) {
			try {
				mouseDownInRoom = null; // Required to prevent unwanted behavior on mouseUp
				if( event.getNativeButton() != NativeEvent.BUTTON_LEFT ) return false;
				if( model.findRoomAt(loc) != null ) return false;
			} catch (Exception exception) {
				exception.printStackTrace();
				return false;
			}
			drawingRectangle  = true;
			highlightControl.enable(false);
			return true;
		}
		
		@Override
		public boolean rectangleChange( Vec2i loc1, Vec2i loc2, MouseEvent<? extends EventHandler> event ) {
			return true;
		}
		
		@Override
		public void rectangleEnd( Vec2i loc1, Vec2i loc2, MouseEvent<? extends EventHandler> event ) {
			try {
				Recti roomArea = new Recti(loc1, loc2);
				if( model.isRoomAreaValid(roomArea) ) {
					HistoryMove historyMove = history.addMoveToHistory( model.addRoom( new Room(roomArea, -1), moveTimer.peekTime() ), model );
					if( historyMove != null ) {
						model.notifyObservers( historyMove.getPuzzleMove() );
						history.notifyObservers( historyMove );
						moveTimer.step();
						moveTimer.notifyObservers();
					}
				}
			} catch (Exception exception) {
				exception.printStackTrace();
			}
			drawingRectangle = false;
			highlightControl.enable(true);
		}
		
	}
	
	private class ClickCallback extends ComponentCallbackAdapter {
		
		@Override
		public boolean mouseDown(Vec2i loc, MouseEvent<? extends EventHandler> event) {		

			Room room;
			try {
				room = model.findRoomAt( loc );
				if( drawingRectangle || room == null ) return false;
				mouseDownInRoom = room;
			} catch (Exception exception) {
				exception.printStackTrace();
			}
			
			return true;
		}
			
		@Override
		public boolean mouseUp(Vec2i loc, MouseEvent<? extends EventHandler> event) {		
		
			try {
				Room room = model.findRoomAt( loc );
				if( drawingRectangle || room == null || room != mouseDownInRoom ) {
					mouseDownInRoom = null;
					return false;
				}
				mouseDownInRoom = null;

				int button = event.getNativeButton();
				if( button == NativeEvent.BUTTON_RIGHT || 
						button == NativeEvent.BUTTON_LEFT && event.isShiftKeyDown() ) {				

					HistoryMove historyMove = history.addMoveToHistory( model.removeRoom( room, moveTimer.peekTime() ), model );
					if( historyMove != null ) {
						model.notifyObservers( historyMove.getPuzzleMove() );
						history.notifyObservers( historyMove );
						moveTimer.step();
						moveTimer.notifyObservers();
					}
				} 
				else if( button == NativeEvent.BUTTON_LEFT ) {
					controller.switchToEditRoomValue(room);
				}
				return true;			
			} catch (Exception exception) {
				exception.printStackTrace();
				return false;
			}
		}
	}
	
	/**
	 * Turns all defaults callbacks on
	 */
	private void enableCallbacks() {
		rectangleControl.addRectangleCallback( roomCallback );			
		view.getControlDecorator().addCellCallback( clickCallback );
	}

	/**
	 * Turns all defaults callbacks off
	 */
	private void disableCallbacks() {
		rectangleControl.deleteRectangleCallback( roomCallback );			
		view.getControlDecorator().removeCellCallback( clickCallback );
	}

	@Override
	public void release() {
		super.release();
		highlightContraints.release();
		if( highlightControl != null )
			highlightControl.release();
		highlightControl = null;
		if( rectangleControl != null )
			rectangleControl.release();
		rectangleControl = null;
		rectHighlighter = null;
		cellHighlighter = null;
	}


}
